library(DBI)
library(dplyr)
library(forcats)
library(ggplot2)
library(ggraph)
library(grid)
library(gridExtra)
library(htmlwidgets)
library(igraph)
library(knitr)
library(kableExtra)
library(readr)
library(SnowballC)
library(stopwords)
library(stringr)
library(tibble)
library(tidyr)
library(tidytext)
library(webshot)
library(widyr)KillDbConnections <- function () {
all_cons <- dbListConnections(PostgreSQL())
for(x in all_cons) + dbDisconnect(x)
}
ReadPresseTablebyYear <- function(table_name, year) {
# Initierung der Datenbank
con <- dbConnect(RPostgreSQL::PostgreSQL(),
host = 'hdm-sql.think-data.de',
dbname = 'postgres',
user = 'postgres',
password = '%%CENSORED%%'
# Der richtige Weg, um auf sichere Weise das Passwort abzufragen
#password = rstudioapi::askForPassword("Database password")
)
# Konstruktion der Query
query <- paste("SELECT * FROM ", table_name, " WHERE filename LIKE '%", year, "%'",sep="")
# Ausführen der Query und Zurückgeben des Ergebnisses
return(dbGetQuery(con, query))
# Verbindungsabbau
KillDbConnections()
}
ReadPresseTable <- function(table_name) {
# Initierung der Datenbank
con <- dbConnect(RPostgreSQL::PostgreSQL(),
host = 'hdm-sql.think-data.de',
dbname = 'postgres',
user = 'postgres',
password = '%%CENSORED%%'
# Der richtige Weg, um auf sichere Weise das Passwort abzufragen
#password = rstudioapi::askForPassword("Database password")
)
# Auslesen der Tabelle und zurückgeben des Ergebnisses
return(dbReadTable(con, table_name))
# Verbindungsabbau
KillDbConnections()
}
# Daten über die Funktion einlesen
presse2009 <- ReadPresseTablebyYear("presse", 2009)
presse <- ReadPresseTable("presse")
kable(head(presse,1)) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F) %>%
scroll_box(width = "100%", height = "200px")| id | header | text | publisher | author | link | filename | year | path |
|---|---|---|---|---|---|---|---|---|
| 1 |
Die Berliner waehlen in Lindgruen und Rosa Zweitstimme ist die wichtige Stimme: Sie entscheidet ueber die tatsaechliche Prozentzahl und ueber die Zahl der Sitze im Parlament/ Erststimme bestimmt den Direktkandidaten in einem Wahlkreis/ Fuer die Bundestagswahl gibt es einen 3. Zettel |
TAZ-Bericht Berlin. Ob das eine versteckte Koalitionsaussage ist? Zufall oder nicht, die BerlinerInnen duerfen bei den Wahlen zum Gesamtberliner Abgeordnetenhaus ausgerechnet rosafarbene und lindgruene Stimmzettel ausfuellen. Auf dem rosa Stimmzettel wird die Erststimme abgegeben, auf dem gruenen die Zweitstimme. Entgegen einem weit verbreiteten Irrtum ist die Zweitstimme die wichtigere, denn sie entscheidet ueber die tatsaechliche Prozentzahl und damit ueber die Zahl der Sitze im Parlament. Mit der Erststimme werden die DirektkandidatInnen der einzelnen Wahlkreise gewaehlt, mit der Zweitstimme Bezirks- oder Landeslisten der Parteien. Ein Direktmandat erhaelt, wer die meisten Stimmen in einem Wahlkreis erringt. Die turnusmaessig wiederkehrende Verwirrung vor Wahlen beim sogenannten Wahlvolk hat sich in diesem Jahr noch dadurch gesteigert, dass die Parteien im Sommer monatelang um die Modalitaeten zur ersten gesamtdeutschen Wahl gestritten haben, an die das Berliner Wahlgesetz angelehnt wurde. Nach der Klage von PDS und den Gruenen vor dem Bundesverfassungsgericht in Karlsruhe musste das erste Wahlgesetz zurueckgezogen werden, das eine allgemeine 5-Prozent-Klausel im gesamten Wahlgebiet und das sogenannte Huckepackverfahren vorsah. Im zweiten Wahlgesetz wurde dann die sogenannte regionalisierte 5-Prozentklausel eingefuehrt. Sie bedeutet, dass zur Bundestagswahl eine Partei entweder im Gebiet der alten oder der neuen Bundeslaender die Sperrklausel ueberwinden muss, um ins Parlament einzuziehen. Im Gebiet der Ex-DDR wurden ausserdem Listenvereinigungen von mehreren Gruppierungen oder Parteien zugelassen, um die Chancen der Buergerbewegungen zu erhoehen. Auch fuer die Wahlen zum Abgeordnetenhaus gelten diese Bedingungen: Ost- und West-Berlin bilden zwar ein einheitliches Wahlgebiet, aber zwei verschiedene Zaehlgebiete. Wer es in einem der beiden Teile schafft, die Sperrklausel zu ueberwinden, sitzt automatisch im Parlament. Die Verwirrung, vor allem in der linksalternativen Waehlerschaft, ist deshalb besonders gross, weil sowohl fuer den Bundestag als auch fuer das Abgeordnetenhaus in beiden Teilen der Stadt die AL, Buendnis 90/Gruene und PDS gewaehlt werden kann. Die PDS hat sich im Sommer bundesweit mit der westlichen Linken Liste/PDS vereinigt und tritt deswegen wie die grossen Parteien CDU und SPD an. Die gruenen Parteien wollten diesen Schritt noch nicht vollziehen, haben in Berlin aber die Moeglichkeit, getrennte Landeslisten fuer das gesamte Wahlgebiet aufzustellen - was auch beide getan haben. Konkret heisst das, man kann sowohl in Schoeneberg wie in Friedrichshain mit der Zweitstimme AL und Buendnis 90 waehlen. Die Stimme ist dann nicht verloren, wenn es die beiden Parteien schaffen, in einem der beiden Zaehlgebiete ueber die Sperrklausel zu kommen - wovon trotz des unklaren Wahlausgangs auszugehen ist. Ob man mit der Erststimme einen Direktkandidaten waehlen kann, haengt davon ab, ob die entsprechende Partei im eigenen Wahlkreis ueberhaupt KandidatInnen nominiert hat. In Berlin koennen insgesamt 200 KandidatInnen in 120 Wahlkreisen gewaehlt werden. Das Berliner Abgeordnetenhaus ist damit das groesste Landesparlament der Republik, dessen Parlamentarierzahl noch durch sogenannte Ueberhangsmandate steigen wird. Ihren Sitz werden die Abgeordneten fuer eine Uebergangsfrist von etwa zwei Jahren weiter im Schoeneberger Rathaus haben. Der an sich zu kleine Plenarsaal wird bis zur konstituierenden Sitzung der neuen Regierung am 11. Januar 1991 notduerftig umgeruestet. Erstmals in der Nachkriegsgeschichte duerfen sich die BerlinerInnen auch an Wahlen zum Bundestag direkt beteiligen, d.h. jedeR darf insgesamt vier Kreuzchen machen. Fuer die Bundestagswahl gibt es einen dritten Stimmzettel, auf dem Erst- und Zweitstimme abgegeben werden. In der oeffentlichen Wahrnehmung in Berlin ist diese Wahl gegenueber den Abgeordnetenhauswahlen so gut wie untergegangen, ueberlagert vom Wahlkampf um die Sitze im Abgeordnetenhaus und die kuenftige Landesregierung. kd | TAZ-BERLIN Nr. 3275 vom 01.12.1990 Seite 37 | kd | https://www.wiso-net.de/document/TAZH__T901201.203 | Presse_1990_01_Html.htm | 1990 | Pressetexte/Presseartikel 1990 |
Dplyr hat auch mittlerweile Funktionen, um Daten von PostgreSQL zu lesen.
KillDbConnections <- function () {
all_cons <- dbListConnections(PostgreSQL())
for(x in all_cons) + dbDisconnect(x)
}
ReadData <- function(table_name, year) {
# Initierung der Datenbank
con <- src_postgres(
host = 'hdm-sql.think-data.de',
dbname = 'postgres',
user = 'postgres',
password = '%%CENSORED%%'
# Der richtige Weg, um auf sichere Weise das Passwort abzufragen
#password = rstudioapi::askForPassword("Database password")
)
# Konstruktion der Query
query <- paste("SELECT * FROM ", table_name, " WHERE filename LIKE '%", year, "%'",sep="")
# Ausführen der Query und Zurückgeben des Ergebnisses
return(tbl(con, sql(query)))
# Verbindungsabbau
KillDbConnections()
}
# Daten über die Funktion einlesen
presse2009_dplyr <- ReadData("presse", 2009)Zuerst werden die Texte über die Publikationen angepasst.
# Anpassen der Daten
presse_cleaned <- presse
# Filtern von Inhalten wie "$publikation vom 01.01.2001 ..."
presse_cleaned$publisher <- gsub(" vom.*$", "", presse_cleaned$publisher, ignore.case = TRUE)
# Filtern von Inhalten wie "$publikation print: Nr. 1 ..."
presse_cleaned$publisher <- gsub(" print: nr. \\d.*$", "", presse_cleaned$publisher, ignore.case = TRUE)
# Filtern von Inhalten wie "$publikation Nr. 1 ..."
presse_cleaned$publisher <- gsub(" nr. \\d.*$", "", presse_cleaned$publisher, ignore.case = TRUE)
# Filtern von Inhalten wie "$publikation, Jg. 52, 01.01.2001 ..."
presse_cleaned$publisher <- gsub(", Jg. \\d.*$", "", presse_cleaned$publisher, ignore.case = TRUE)
# Filtern von Inhalten wie "$publikation, 01.01.2001, S. 1 ..."
presse_cleaned$publisher <- gsub(", \\d\\d.\\d\\d.\\d\\d\\d\\d.*$", "", presse_cleaned$publisher, ignore.case = TRUE)
# Filtern von Inhalten wie "$publikation Nr. ..."
presse_cleaned$publisher <- gsub("Nr. *$", "", presse_cleaned$publisher, ignore.case = TRUE)
# Vereinheitlichen der Groß- und Kleinschreibung
# Entfernen aller Leerzeichen vor und nach den Publikationen
presse_cleaned$publisher <- tolower(presse_cleaned$publisher) %>% trimws()Anschließend werden die Umlaute ä, ö, ü und ß vereinheitlicht, da die Artikel zum einen “ü” als “ue” und zum anderen “ü” als “ü” darstellen. Um eine Verzerrung - beispielsweise im Fall der Partei ‘Die Grünen’ - auszuschließen, wird die Schreibweise “ue” für alle Inhalte vereinheitlicht.
presse_cleaned$header <- gsub("ß", "ss", presse_cleaned$header, ignore.case = TRUE)
presse_cleaned$text <- gsub("ß", "ss", presse_cleaned$text, ignore.case = TRUE)
presse_cleaned$header <- gsub("ä", "ae", presse_cleaned$header, ignore.case = TRUE)
presse_cleaned$text <- gsub("ä", "ae", presse_cleaned$text, ignore.case = TRUE)
presse_cleaned$header <- gsub("ö", "oe", presse_cleaned$header, ignore.case = TRUE)
presse_cleaned$text <- gsub("ö", "oe", presse_cleaned$text, ignore.case = TRUE)
presse_cleaned$header <- gsub("ü", "ue", presse_cleaned$header, ignore.case = TRUE)
presse_cleaned$text <- gsub("ü", "ue", presse_cleaned$text, ignore.case = TRUE)# Extraktion der Token aus den Artikelüberschriften
token_header <- unnest_tokens(as_tibble(presse_cleaned), word, header, token = "words", format = "text", to_lower = TRUE, drop = TRUE)
# Extraktion der Token aus den Artikeltexten
token_text <- unnest_tokens(as_tibble(presse_cleaned), word, text, token = "words", format = "text", to_lower = TRUE, drop = TRUE)
# Visualisierung der Ergebnisse der Prozeduren
kable(head(token_header,1)) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F) %>%
scroll_box(width = "100%", height = "200px")| id | text | publisher | author | link | filename | year | path | word |
|---|---|---|---|---|---|---|---|---|
| 1 | TAZ-Bericht Berlin. Ob das eine versteckte Koalitionsaussage ist? Zufall oder nicht, die BerlinerInnen duerfen bei den Wahlen zum Gesamtberliner Abgeordnetenhaus ausgerechnet rosafarbene und lindgruene Stimmzettel ausfuellen. Auf dem rosa Stimmzettel wird die Erststimme abgegeben, auf dem gruenen die Zweitstimme. Entgegen einem weit verbreiteten Irrtum ist die Zweitstimme die wichtigere, denn sie entscheidet ueber die tatsaechliche Prozentzahl und damit ueber die Zahl der Sitze im Parlament. Mit der Erststimme werden die DirektkandidatInnen der einzelnen Wahlkreise gewaehlt, mit der Zweitstimme Bezirks- oder Landeslisten der Parteien. Ein Direktmandat erhaelt, wer die meisten Stimmen in einem Wahlkreis erringt. Die turnusmaessig wiederkehrende Verwirrung vor Wahlen beim sogenannten Wahlvolk hat sich in diesem Jahr noch dadurch gesteigert, dass die Parteien im Sommer monatelang um die Modalitaeten zur ersten gesamtdeutschen Wahl gestritten haben, an die das Berliner Wahlgesetz angelehnt wurde. Nach der Klage von PDS und den Gruenen vor dem Bundesverfassungsgericht in Karlsruhe musste das erste Wahlgesetz zurueckgezogen werden, das eine allgemeine 5-Prozent-Klausel im gesamten Wahlgebiet und das sogenannte Huckepackverfahren vorsah. Im zweiten Wahlgesetz wurde dann die sogenannte regionalisierte 5-Prozentklausel eingefuehrt. Sie bedeutet, dass zur Bundestagswahl eine Partei entweder im Gebiet der alten oder der neuen Bundeslaender die Sperrklausel ueberwinden muss, um ins Parlament einzuziehen. Im Gebiet der Ex-DDR wurden ausserdem Listenvereinigungen von mehreren Gruppierungen oder Parteien zugelassen, um die Chancen der Buergerbewegungen zu erhoehen. Auch fuer die Wahlen zum Abgeordnetenhaus gelten diese Bedingungen: Ost- und West-Berlin bilden zwar ein einheitliches Wahlgebiet, aber zwei verschiedene Zaehlgebiete. Wer es in einem der beiden Teile schafft, die Sperrklausel zu ueberwinden, sitzt automatisch im Parlament. Die Verwirrung, vor allem in der linksalternativen Waehlerschaft, ist deshalb besonders gross, weil sowohl fuer den Bundestag als auch fuer das Abgeordnetenhaus in beiden Teilen der Stadt die AL, Buendnis 90/Gruene und PDS gewaehlt werden kann. Die PDS hat sich im Sommer bundesweit mit der westlichen Linken Liste/PDS vereinigt und tritt deswegen wie die grossen Parteien CDU und SPD an. Die gruenen Parteien wollten diesen Schritt noch nicht vollziehen, haben in Berlin aber die Moeglichkeit, getrennte Landeslisten fuer das gesamte Wahlgebiet aufzustellen - was auch beide getan haben. Konkret heisst das, man kann sowohl in Schoeneberg wie in Friedrichshain mit der Zweitstimme AL und Buendnis 90 waehlen. Die Stimme ist dann nicht verloren, wenn es die beiden Parteien schaffen, in einem der beiden Zaehlgebiete ueber die Sperrklausel zu kommen - wovon trotz des unklaren Wahlausgangs auszugehen ist. Ob man mit der Erststimme einen Direktkandidaten waehlen kann, haengt davon ab, ob die entsprechende Partei im eigenen Wahlkreis ueberhaupt KandidatInnen nominiert hat. In Berlin koennen insgesamt 200 KandidatInnen in 120 Wahlkreisen gewaehlt werden. Das Berliner Abgeordnetenhaus ist damit das groesste Landesparlament der Republik, dessen Parlamentarierzahl noch durch sogenannte Ueberhangsmandate steigen wird. Ihren Sitz werden die Abgeordneten fuer eine Uebergangsfrist von etwa zwei Jahren weiter im Schoeneberger Rathaus haben. Der an sich zu kleine Plenarsaal wird bis zur konstituierenden Sitzung der neuen Regierung am 11. Januar 1991 notduerftig umgeruestet. Erstmals in der Nachkriegsgeschichte duerfen sich die BerlinerInnen auch an Wahlen zum Bundestag direkt beteiligen, d.h. jedeR darf insgesamt vier Kreuzchen machen. Fuer die Bundestagswahl gibt es einen dritten Stimmzettel, auf dem Erst- und Zweitstimme abgegeben werden. In der oeffentlichen Wahrnehmung in Berlin ist diese Wahl gegenueber den Abgeordnetenhauswahlen so gut wie untergegangen, ueberlagert vom Wahlkampf um die Sitze im Abgeordnetenhaus und die kuenftige Landesregierung. kd | taz-berlin | kd | https://www.wiso-net.de/document/TAZH__T901201.203 | Presse_1990_01_Html.htm | 1990 | Pressetexte/Presseartikel 1990 | die |
kable(head(token_text,1)) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F) %>%
scroll_box(width = "100%", height = "200px")| id | header | publisher | author | link | filename | year | path | word |
|---|---|---|---|---|---|---|---|---|
| 1 |
Die Berliner waehlen in Lindgruen und Rosa Zweitstimme ist die wichtige Stimme: Sie entscheidet ueber die tatsaechliche Prozentzahl und ueber die Zahl der Sitze im Parlament/ Erststimme bestimmt den Direktkandidaten in einem Wahlkreis/ Fuer die Bundestagswahl gibt es einen 3. Zettel |
taz-berlin | kd | https://www.wiso-net.de/document/TAZH__T901201.203 | Presse_1990_01_Html.htm | 1990 | Pressetexte/Presseartikel 1990 | taz |
# Liste mit deutschen Stopwörtern
stopword <- as_tibble(stopwords::stopwords("de"))
stopword <- rename(stopword, word=value)
# Erweiterte Liste mit deutschen Stopwörtern
stopword_extented <- read_tsv("https://raw.githubusercontent.com/solariz/german_stopwords/master/german_stopwords_full.txt", col_names = FALSE, comment = ";")
stopword_extented <- rename(stopword_extented, word=X1)
# Liste eigener Stopwörtern
# bz ist das Kürzel der Badischen Zeitung
# mz ist das Kürzel der Mitteldeutsche Zeitung
# rp ist das Kürzel der Rheinischen Post
# sz ist das Kürzel der Sächsische Zeitung
# ta ist das Kürzel der Thüringer Allgemeinen
# taz ist das Kürzel der tageszeitung
# tz ist das Kürzel der tz - eine münchner zeitung
stopword_own <- tibble(word = c("bz", "mz", "rp", "sz", "tz", "ta", "taz"))
# Zusammenfügen und Entfernen von Duplikaten
all_stopword <- bind_rows(stopword,stopword_extented, stopword_own) %>% distinct()
tb_header <- anti_join(token_header, all_stopword, by = 'word')
tb_text <- anti_join(token_text, all_stopword, by = 'word')
# Visualisierung der Ergebnisse der Prozeduren
kable(head(tb_header,1)) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F) %>%
scroll_box(width = "100%", height = "200px")| id | text | publisher | author | link | filename | year | path | word |
|---|---|---|---|---|---|---|---|---|
| 1 | TAZ-Bericht Berlin. Ob das eine versteckte Koalitionsaussage ist? Zufall oder nicht, die BerlinerInnen duerfen bei den Wahlen zum Gesamtberliner Abgeordnetenhaus ausgerechnet rosafarbene und lindgruene Stimmzettel ausfuellen. Auf dem rosa Stimmzettel wird die Erststimme abgegeben, auf dem gruenen die Zweitstimme. Entgegen einem weit verbreiteten Irrtum ist die Zweitstimme die wichtigere, denn sie entscheidet ueber die tatsaechliche Prozentzahl und damit ueber die Zahl der Sitze im Parlament. Mit der Erststimme werden die DirektkandidatInnen der einzelnen Wahlkreise gewaehlt, mit der Zweitstimme Bezirks- oder Landeslisten der Parteien. Ein Direktmandat erhaelt, wer die meisten Stimmen in einem Wahlkreis erringt. Die turnusmaessig wiederkehrende Verwirrung vor Wahlen beim sogenannten Wahlvolk hat sich in diesem Jahr noch dadurch gesteigert, dass die Parteien im Sommer monatelang um die Modalitaeten zur ersten gesamtdeutschen Wahl gestritten haben, an die das Berliner Wahlgesetz angelehnt wurde. Nach der Klage von PDS und den Gruenen vor dem Bundesverfassungsgericht in Karlsruhe musste das erste Wahlgesetz zurueckgezogen werden, das eine allgemeine 5-Prozent-Klausel im gesamten Wahlgebiet und das sogenannte Huckepackverfahren vorsah. Im zweiten Wahlgesetz wurde dann die sogenannte regionalisierte 5-Prozentklausel eingefuehrt. Sie bedeutet, dass zur Bundestagswahl eine Partei entweder im Gebiet der alten oder der neuen Bundeslaender die Sperrklausel ueberwinden muss, um ins Parlament einzuziehen. Im Gebiet der Ex-DDR wurden ausserdem Listenvereinigungen von mehreren Gruppierungen oder Parteien zugelassen, um die Chancen der Buergerbewegungen zu erhoehen. Auch fuer die Wahlen zum Abgeordnetenhaus gelten diese Bedingungen: Ost- und West-Berlin bilden zwar ein einheitliches Wahlgebiet, aber zwei verschiedene Zaehlgebiete. Wer es in einem der beiden Teile schafft, die Sperrklausel zu ueberwinden, sitzt automatisch im Parlament. Die Verwirrung, vor allem in der linksalternativen Waehlerschaft, ist deshalb besonders gross, weil sowohl fuer den Bundestag als auch fuer das Abgeordnetenhaus in beiden Teilen der Stadt die AL, Buendnis 90/Gruene und PDS gewaehlt werden kann. Die PDS hat sich im Sommer bundesweit mit der westlichen Linken Liste/PDS vereinigt und tritt deswegen wie die grossen Parteien CDU und SPD an. Die gruenen Parteien wollten diesen Schritt noch nicht vollziehen, haben in Berlin aber die Moeglichkeit, getrennte Landeslisten fuer das gesamte Wahlgebiet aufzustellen - was auch beide getan haben. Konkret heisst das, man kann sowohl in Schoeneberg wie in Friedrichshain mit der Zweitstimme AL und Buendnis 90 waehlen. Die Stimme ist dann nicht verloren, wenn es die beiden Parteien schaffen, in einem der beiden Zaehlgebiete ueber die Sperrklausel zu kommen - wovon trotz des unklaren Wahlausgangs auszugehen ist. Ob man mit der Erststimme einen Direktkandidaten waehlen kann, haengt davon ab, ob die entsprechende Partei im eigenen Wahlkreis ueberhaupt KandidatInnen nominiert hat. In Berlin koennen insgesamt 200 KandidatInnen in 120 Wahlkreisen gewaehlt werden. Das Berliner Abgeordnetenhaus ist damit das groesste Landesparlament der Republik, dessen Parlamentarierzahl noch durch sogenannte Ueberhangsmandate steigen wird. Ihren Sitz werden die Abgeordneten fuer eine Uebergangsfrist von etwa zwei Jahren weiter im Schoeneberger Rathaus haben. Der an sich zu kleine Plenarsaal wird bis zur konstituierenden Sitzung der neuen Regierung am 11. Januar 1991 notduerftig umgeruestet. Erstmals in der Nachkriegsgeschichte duerfen sich die BerlinerInnen auch an Wahlen zum Bundestag direkt beteiligen, d.h. jedeR darf insgesamt vier Kreuzchen machen. Fuer die Bundestagswahl gibt es einen dritten Stimmzettel, auf dem Erst- und Zweitstimme abgegeben werden. In der oeffentlichen Wahrnehmung in Berlin ist diese Wahl gegenueber den Abgeordnetenhauswahlen so gut wie untergegangen, ueberlagert vom Wahlkampf um die Sitze im Abgeordnetenhaus und die kuenftige Landesregierung. kd | taz-berlin | kd | https://www.wiso-net.de/document/TAZH__T901201.203 | Presse_1990_01_Html.htm | 1990 | Pressetexte/Presseartikel 1990 | berliner |
kable(head(tb_text,1)) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F) %>%
scroll_box(width = "100%", height = "200px")| id | header | publisher | author | link | filename | year | path | word |
|---|---|---|---|---|---|---|---|---|
| 1 |
Die Berliner waehlen in Lindgruen und Rosa Zweitstimme ist die wichtige Stimme: Sie entscheidet ueber die tatsaechliche Prozentzahl und ueber die Zahl der Sitze im Parlament/ Erststimme bestimmt den Direktkandidaten in einem Wahlkreis/ Fuer die Bundestagswahl gibt es einen 3. Zettel |
taz-berlin | kd | https://www.wiso-net.de/document/TAZH__T901201.203 | Presse_1990_01_Html.htm | 1990 | Pressetexte/Presseartikel 1990 | bericht |
tb_text_stem <- tb_text %>%
mutate(word_stem = wordStem(.$word, language = "german")) %>%
dplyr::count(word_stem, sort = TRUE)
graph1 <- tb_text_stem %>%
top_n(10) %>%
ggplot() +
aes(x = reorder(word_stem, n), y = n) +
geom_col() +
labs(title = "mit Stemming") +
coord_flip() +
theme(axis.title.y=element_blank())
graph2 <- tb_text %>%
dplyr::count(word, sort = TRUE) %>%
top_n(10) %>%
ggplot() +
aes(x = reorder(word, n), y = n) +
geom_col() +
labs(title = "ohne Stemming") +
coord_flip() +
theme(axis.title.y=element_blank())
grid.arrange(graph1,graph2, ncol=2, nrow=1,
top = textGrob("Wörter in den Artikeltexten",gp=gpar(fontsize=18)))Wenig überraschend tauchen die Namen der Parteien und Begriffen wie ‘bundestagswahl’, ‘wahl’ oder ‘prozent’ eine herausragende Rolle. Zwischen einer Analyse mit oder ohne Stemming besteht kein wesentlicher Unterschied.
tb_header_stem <- tb_header %>%
mutate(word_stem = wordStem(.$word, language = "german")) %>%
dplyr::count(word_stem, sort = TRUE)
graph1 <- tb_header_stem %>%
top_n(10) %>%
ggplot() +
aes(x = reorder(word_stem, n), y = n) +
geom_col() +
labs(title = "mit Stemming") +
coord_flip() +
theme(axis.title.y=element_blank())
graph2 <- tb_header %>%
dplyr::count(word, sort = TRUE) %>%
top_n(10) %>%
ggplot() +
aes(x = reorder(word, n), y = n) +
geom_col() +
labs(title = "ohne Stemming") +
coord_flip() +
theme(axis.title.y=element_blank())
grid.arrange(graph1,graph2, ncol=2, nrow=1,
top = textGrob("Wörter in den Artikelüberschriften",gp=gpar(fontsize=18)))Die Situation bei den Wörtern in den Überschriften unterscheidet sich nicht wesentlich. Insgesamt aber scheint die Aufbereitung mit Stemming leicht stabiler zu sein. Deshalb werden in den nachfolgenden Kapiteln ausschließlich gestemmte Wörter benutzt.
# Überschreiben der Dataframes mit den gestemmten Daten
tb_text_stem <- tb_text %>%
mutate(word_stem = wordStem(.$word, language = "german"))
tb_header_stem <- tb_header %>%
mutate(word_stem = wordStem(.$word, language = "german"))word_count_header <- count(tb_header, word, sort = TRUE)
word_count_text <- count(tb_text, word, sort = TRUE)
word_count_header %>%
top_n(10) %>%
ggplot() +
aes(x = reorder(word, n), y = n) +
geom_col() +
labs(title = "Top 10 Wörter in den Artikelüberschriften") +
coord_flip() +
theme(axis.title.y=element_blank())word_count_text %>%
top_n(10) %>%
ggplot() +
aes(x = reorder(word, n), y = n) +
geom_col() +
labs(title = "Top 10 Wörter in den Artikeltexten") +
coord_flip() +
theme(axis.title.y=element_blank())# Anzahl der Artikel pro Publikation
publisher_articles_count <- count(tb_text, publisher, sort = TRUE)
# Anzahl der Token der Artikeltexte pro Publikation
publisher_articles_word_text_count <- count(tb_text, publisher, word, sort = TRUE)
# Anzahl der Token in den Artikelüberschriften pro Publikation
publisher_articles_word_header_count <- count(tb_header, publisher, word, sort = TRUE)
# Artikel pro Publikation
kable(head(publisher_articles_count[order(-publisher_articles_count$n),])) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F)| publisher | n |
|---|---|
| mitteldeutsche zeitung | 164548 |
| welt online | 138942 |
| zeit online | 115527 |
| der tagesspiegel | 102536 |
| badische zeitung | 96158 |
| rheinische post | 85634 |
# Top Token aus den Artikeltexten pro Publikation
kable(head(publisher_articles_word_text_count[order(-publisher_articles_word_text_count$n),])) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F)| publisher | word | n |
|---|---|---|
| mitteldeutsche zeitung | fã | 3993 |
| mitteldeutsche zeitung | r | 3791 |
| welt online | fã | 3393 |
| welt online | r | 3067 |
| zeit online | fã | 2600 |
| zeit online | r | 2262 |
# Top Token aus den Artikelüberschriften pro Publikation
kable(head(publisher_articles_word_header_count[order(-publisher_articles_word_header_count$n),])) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F)| publisher | word | n |
|---|---|---|
| rheinische post | bundestagswahl | 533 |
| badische zeitung | bundestagswahl | 391 |
| sã¤chsische zeitung | bundestagswahl | 355 |
| thã¼ringer allgemeine | bundestagswahl | 308 |
| mitteldeutsche zeitung | bundestagswahl | 261 |
| sã¤chsische zeitung | thema | 214 |
article_patei_cdu_count <- tb_text %>% filter(word == "cdu"|word == "csu") %>% group_by(year) %>% count(year, sort = TRUE) %>% ungroup()
article_patei_cdu_count$word <- "cdu"
article_patei_spd_count <- tb_text %>% filter(word == "spd") %>% group_by(year) %>% count(word, sort = TRUE) %>% ungroup()
article_patei_gruene_count <- tb_text %>% filter(word == "gruenen"|word == "b90") %>% group_by(year) %>% count(year, sort = TRUE) %>% ungroup()
article_patei_gruene_count$word <- "gruene"
article_patei_fdp_count <- tb_text %>% filter(word == "fdp") %>% group_by(year) %>% count(word, sort = TRUE) %>% ungroup()
article_patei_afd_count <- tb_text %>% filter(word == "afd") %>% group_by(year) %>% count(word, sort = TRUE) %>% ungroup()
article_patei_linke_count <- tb_text %>% filter(word == "linken" | word == "pds") %>% group_by(year) %>% count(year, sort = TRUE) %>% ungroup()
article_patei_linke_count$word <- "linke"
article_patei_total <- rbind(article_patei_cdu_count,
article_patei_spd_count,
article_patei_fdp_count,
article_patei_gruene_count,
article_patei_linke_count,
article_patei_afd_count)
article_patei_percent <- group_by(article_patei_total, year) %>%
mutate(percent = n/sum(n) * 100) %>%
ungroup()
pateifarben <- c("blue", "black", "yellow", "green", "purple", "red")
ggplot(data=article_patei_percent, aes(x=year, y=percent, fill=word )) +
geom_bar(stat="identity",
position='stack')+
scale_fill_manual(values=pateifarben) +
xlab("Nennungen in der Presse") +
ylab("Prozent") +
theme_minimal() +
theme(legend.title = element_blank()) +
ggtitle("Pressepräsenz der Parteien im Vergleich")Die Visualisierung verdeutlicht die Präsenz der verschiedenen Parteien in der Presse im Vorfeld der Bundestagswahlen. Über den Betrachtungszeitraum schwankt die Pressepräsenz der Parteien zum Teil deutlich. Besonders deutlich wird das in den frühen 2000 Jahren bei der Linkspartei oder in der jüngsten Vergangenheit bei der AFD. Insgesamt lässt sich beobachten, dass kleinere Parteien wie FDP oder Grüne in der Presse recht gut vertreten sind - zumindest wenn man die Pressepräsenz mit dem prozentualen Abschneiden bei der Wahl vergleicht. Ebenfalls interessant ist zu beobachten, dass die Regierungsparteien etwas stärker in der Presse präsent sind als die Opposition - beispielsweise die Union in den 1990er Jahren oder die SDP während der Regierungszeit Gehard Schröders.
# Funktion, um die Wahlergebnisse der jeweiligen Partei einzulesen
read_wahlergebnis <- function(partei) {
z <- read_csv2("https://raw.githubusercontent.com/TheFakeStefan/DataSciencewithR/master/data/bundestagswahlergebnisse_1990_2017.csv",
col_type = cols()) %>%
select(Wahljahr,toupper(partei)) %>%
as.data.frame() %>%
rename("year" = Wahljahr, "percent" = toupper(partei))
z$type <- "r"
z$word <- tolower(partei)
z$n <- 0
return(z)
}
# Anwenden der Funktion
wahlergbnis_cdu <- read_wahlergebnis("CDU")
wahlergbnis_spd <- read_wahlergebnis("SPD")
wahlergbnis_linke <- read_wahlergebnis("LINKE")
wahlergbnis_gruene <- read_wahlergebnis("GRUENE")
wahlergbnis_afd <- read_wahlergebnis("AFD")
wahlergbnis_sonstige <- read_wahlergebnis("SONSTIGE")
wahlergbnis_fdp <- read_wahlergebnis("FDP")
# Zusammenführen der Daten
wahlergbnis_patei_percent <- rbind(wahlergbnis_cdu,
wahlergbnis_spd,
wahlergbnis_fdp,
wahlergbnis_gruene,
wahlergbnis_linke,
wahlergbnis_afd,
wahlergbnis_sonstige)
# Zusammenführen mit den Pressedaten
article_patei_percent$type <- "p"
graphdata <- rbind(article_patei_percent,wahlergbnis_patei_percent)
# Vorbereitende Formatierungsarbeiten
graphdata$word <- toupper(graphdata$word)
# Richtige Farbkennung der Parteien
pateifarben <- c("blue", "black", "yellow", "green", "purple", "grey", "red")
# Plotten der Grafik
ggplot(data=graphdata, aes(x=type, y=percent, fill=word )) +
geom_bar(stat="identity",
position='stack')+
facet_grid( ~ year) +
scale_fill_manual(values=pateifarben) +
xlab("(P)resse VS (R)ealität") +
ylab("Prozent") +
labs(caption = "... auf Basis der Nennungen in den Artikeltexten.") +
theme_minimal() +
theme(legend.title = element_blank()) +
ggtitle("Vergleich der Wahlergebnisse mit der Relevanz in der Presse")Das oben Gesagte bestätigt sich zum Teil bei dieser direkten Gegenüberstellung von Pressepräsenz und Wahlergebnissen. Auffällig ist die Situation der Volksparteien. Die Union schnitt prozentual bei den letzten acht Bundestagswahlen besser ab als als es ihre relative Pressepräsenz vermuten ließe. Bei der SPD ist die Situation gemischt. Bis 2002 waren ihre Wahlergebnisse besser als ihre Pressepräsenz, seither ist es umgekehrt. Die FDP, die Linkspartei und zum Teil auch die Grünen zeichnen sich dadurch aus, dass ihre Pressepräsenz stärker ausgeprägt ist als ihr tatsächlicher Wahlerfolg.
publisher_articles_count <- count(tb_text, publisher, sort =T) %>% top_n(10)
xlim <- c(0, 1.1*max(publisher_articles_count$n))
par(mar=c(5,8,4,1)+.1)
xx <- barplot(publisher_articles_count$n,
main = "Anzahl der Artikel nach Verlagen",
xlab = "Anzahl der Artikel",
horiz = T,
col = "lightblue")
# Text in den Balken des Balkendiagramms
text(y= xx, x = publisher_articles_count$n, label = publisher_articles_count$n, pos = 2, cex = 1.0, col = "black")
# y-Achse und Labels
axis(side=2, at=xx, labels = publisher_articles_count$publisher, las=1, cex.axis=0.7)Bei der Betrachtung des Balkendiagramms fällt auf, dass die Mitteldeutsche Zeitung mit einer sehr großen Anzahl von Beiträgen vertreten ist. Dieses könnte auch daran liegen, dass die Publikation seit langem in der WISO-Datenbank vertreten ist und vermutliche zahlreiche lokale Unterausgaben als einzelne Artikel gerechnet werden.
publisher_articles_count <- count(tb_text, publisher, sort =T) %>% top_n(10) %>%
rename(total_articles = n)
wortanzahl_article <- tb_text %>% group_by(publisher,id) %>% tally(name = "wortanzahl")
wortanzahl_article_pro_publikation <-
aggregate(wortanzahl_article$wortanzahl, by=list(wortanzahl_article$publisher), mean) %>%
rename(publisher = Group.1,mean_wortanzahl = x)
publisher_articles_count_mean <- merge(x=publisher_articles_count,y=wortanzahl_article_pro_publikation,by="publisher")
publisher_articles_count_mean_plot <- barplot(as.matrix(publisher_articles_count_mean$mean_wortanzahl),
main = "Anzahl der durchschnittlichen Wörter in einem Artikel pro Publikation",
xlab = "Anzahl der Wörter",
horiz = T,
col = "lightblue",
beside=TRUE)
# y-Achse und Labels
axis(side=2, at=publisher_articles_count_mean_plot, labels = publisher_articles_count$publisher, las=1, cex.axis=0.7)Augenfällig ist in dieser Darstellung, dass die Artikel von Online-Publikationen im Durchschnitt deutlich kürzer sind als Artikel aus Printmedien.
articles_word_text_count <- tb_text %>% count(word)
articles_word_text_count_n1 <- tb_text %>% count(word) %>% filter(n == 1) %>% summarise("Gesamtanzahl der Token, welche 1x vorkommen" = sum(n))
kable(articles_word_text_count_n1)| Gesamtanzahl der Token, welche 1x vorkommen |
|---|
| 19973 |
hist(articles_word_text_count$n,
breaks=40,
main="Verteilung der Token in den Artikeltexten",
xlab="Häufigkeit der Tokens",
ylab="Verteilung",
col="blue",
)Es ist deutlich zu erkennen, dass circa 42.500 Token lediglich einmal vorkommen. Daher werden im Nachfolgenden alle Token herausgefiltert, welche nicht mindestens 50x vorkommen.
articles_word_text_count_without_n50 <-
publisher_articles_word_text_count %>%
filter(n > 49 )
hist(articles_word_text_count_without_n50$n,
breaks=40,
main="Verteilung der Token (n > 49) in den Artikeltexten",
sub="42,5k Token kommen weniger 50x vor",
xlab="Häufigkeit der Tokens",
ylab="Verteilung",
col="blue",
)1.000 Token kommen mehr als 50x in den Artikeltexten vor. Auch hier zeigt sich eine rechtsschiefe Verteilung, allerdings bei Weitem nicht so extrem ausgeprägt wie vor dem Herausfiltern von Wörtern mit weniger als 50 Nennungen.
articles_word_header_count <- tb_header %>% count(word)
articles_word_header_count_n1 <- tb_header %>% count(word) %>% filter(n == 1) %>% summarise("Gesamtanzahl der Token, welche 1x vorkommen" = sum(n))
kable(articles_word_header_count_n1)| Gesamtanzahl der Token, welche 1x vorkommen |
|---|
| 3021 |
hist(articles_word_header_count$n,
breaks=40,
main="Verteilung der Token in den Artikelüberschriften",
xlab="Häufigkeit der Tokens",
ylab="Verteilung",
col="blue",
)Es ist deutlich zu erkennen, dass circa 4.700 Token in den Artikelüberschriften lediglich einmal vorkommen. Daher werden im Nachfolgenden alle Token herausgefiltert, welche nicht mindestens 10x vorkommen.
articles_word_header_count_n10 <-
articles_word_header_count %>%
filter(n > 9 )
hist(articles_word_header_count_n10$n,
breaks=40,
main="Verteilung der Token (n > 9) in den Artikelüberschriften",
xlab="Häufigkeit der Tokens",
ylab="Verteilung",
col="blue",
)Übrig bleiben 369 Token in den Artikelüberschriften, welche mehr als 10x vorgekamen. Auch hier zeigt sich eine ausgeprägt rechtsschiefe Verteilung.
# Anzahl der Artikel nach Jahren
year_articles_count <- count(tb_text, year, sort = TRUE)
# Anzahl der Token in den Artikeltexten nach Jahren
year_articles_word_text_count <- count(tb_text, year, word, sort = TRUE)
# Anzahl der Token in den Artikelüberschriften nach Jahren
year_articles_word_header_count <- count(tb_header, year, word, sort = TRUE)
# Artikel nach Jahren
kable(head(year_articles_count[order(-year_articles_count$n),])) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F)| year | n |
|---|---|
| 2017 | 706818 |
| 2013 | 345166 |
| 2005 | 162863 |
| 2009 | 138801 |
| 2002 | 59804 |
| 1998 | 52435 |
# Top Token in den Artikeltexten nach Jahren
kable(head(year_articles_word_text_count[order(-year_articles_word_text_count$n),])) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F)| year | word | n |
|---|---|---|
| 2017 | fã | 16212 |
| 2017 | r | 15038 |
| 2017 | ã | 8316 |
| 2013 | fã | 7636 |
| 2017 | wã | 6898 |
| 2013 | r | 6874 |
# Top Token in den Artikelüberschriften nach Jahren
kable(head(year_articles_word_header_count[order(-year_articles_word_header_count$n),])) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = F)| year | word | n |
|---|---|---|
| 2005 | bundestagswahl | 859 |
| 2017 | bundestagswahl | 850 |
| 2013 | bundestagswahl | 820 |
| 2009 | bundestagswahl | 788 |
| 2017 | fã | 282 |
| 2005 | fã | 277 |
Die Visualisierung zeigt deutlich, dass die Anzahl der Artikel über den Betrachtungszeitraum deutlich zugenommen hat. Dieses ist jedoch eher auf den Ausbau der WISO-Datenbank über die Jahre zurückzuführen als auf den tatsächlichen Umfang der Berichterstattung.
In diesem Abschnitt sollen relevante Themen der Wahljahre identifiziert werden. Dazu werden spezielle Stopwörter verwendet, um Parteien und häufige themenirrelevante Begriffe zu entfernen.
themen_der_wahlen <- tb_text %>%
filter(!word %in% c("afd","berlin","bonn","bundestag","bundestagswahl","buendnis","cdu", "csu",
"dezember","fdp", "gruene","gruenen","jahren","kandidaten","linke","oktober",
"partei","parteien","pds","prozent", "september","spd","thema", "uhr","union",
"wahl","wahlkreis","waehlen","waehler") &
!str_detect(word, pattern = "[[:digit:]]"))
themen_der_wahlen_top5_count <-
themen_der_wahlen %>%
count(word, year) %>%
group_by(year) %>%
top_n(n=5)
themen_der_wahlen_top5_count %>%
ggplot(aes(word, n, fill = as.factor(year))) +
scale_y_continuous(expand = c(0, 0)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y = "n") +
coord_flip() +
theme_classic(base_size = 12) +
labs(fill= "Wahljahr",
title = "Top5 Token der Wahljahre",
subtitle="in den Artikeltexten",
x= NULL,
y= "Häufigkeit") +
theme(plot.title = element_text(lineheight=.8, face="bold")) +
scale_fill_brewer(palette="Set1") +
facet_wrap(~year,scales='free', ncol=2)Die Aufstellung der Top5 Begriffe verdeutlich zum einen, welche der handelnden Personen bei der jeweiligen Wahl im Zentrum des Interesses standen. Vereinzelt kann man auch Hinweise auf dominierende Themen erkennen, so zum Beispiel im Jahre 1990 die noch frische Erinnerung an die DDR, im Jahr 2005 das Thema Arbeit (Agenda 2010 und Hartz-Reformen), sowie im Jahr 2002 das Aufkommen der Schill-Partei in Hamburg.
bigram_header_2017 <- presse_cleaned %>%
filter(year == "2017") %>%
unnest_tokens(bigram, header, token = "ngrams", n = 2)
bigram_header_2017 %>%
count(bigram, sort = TRUE) %>%
top_n(10) %>%
mutate(bigram = reorder(bigram, n)) %>%
ggplot(aes(bigram, n)) +
geom_col() +
xlab(NULL) +
ylab("Häufigkeit (n)") +
coord_flip() +
theme_minimal()Ohne den Ausschluss von Stopwords ist diese Analyse nicht sonderlich aussagekräftig.
bigram_texts_zeit_online_2017 <- presse_cleaned %>%
filter(publisher == "badische zeitung" | publisher == "zeit online") %>%
unnest_tokens(bigram, header, token = "ngrams", n = 2)
bigram_texts_zeit_online_2017 %>%
count(bigram, sort = TRUE) %>%
top_n(10) %>%
mutate(bigram = reorder(bigram, n)) %>%
ggplot(aes(bigram, n)) +
geom_col() +
xlab(NULL) +
ylab("Häufigkeit (n)") +
labs(title="Top10 Token für die Wahljahre",
subtitle="aus dem Jahr 2017 der Verlage Badische Zeitung und Zeit Online") +
coord_flip() +
theme_classic()Die Visualisierung zeigt leider nur häufig verwendete Artikel, Präpositionen, Bindewörter und andere Wortkombinationen, welche zu großen Teilen Stopwörter der deutschen Sprache sind. Die Stopwörter werden erst nach dem Zerlegen der Token angewendet. In diesem Fall müssen die bigrams genauer betrachtet werden und Stopwörter von diesen entfernt werden.
bigram_texts_zeit_online_2017_separated <- bigram_texts_zeit_online_2017 %>%
separate(bigram, c("word1", "word2"), sep = " ")
bigram_texts_zeit_online_2017_filtered <- bigram_texts_zeit_online_2017_separated %>%
filter(!word1 %in% all_stopword$word) %>%
filter(!word2 %in% all_stopword$word) %>%
filter(!is.na(word1))
bigram_texts_zeit_online_2017_counts <- bigram_texts_zeit_online_2017_filtered %>%
count(word1, word2, sort = TRUE)
bigram_texts_zeit_online_2017_united <- bigram_texts_zeit_online_2017_filtered %>%
unite(bigram, word1, word2, sep = " ")
bigram_texts_zeit_online_2017_united %>%
count(bigram, sort = TRUE) %>%
top_n(9) %>%
mutate(bigram = reorder(bigram, n)) %>%
ggplot(aes(bigram, n)) +
geom_col() +
xlab(NULL) +
ylab("Häufigkeit (n)") +
coord_flip() +
theme_minimal()Die Darstellung ist wesentlich besser, jedoch sind vermehrt die Daten der vergangenen Wahltage als bigrams zu sehen. Daher werden im Nachfolgenden auch die Zahlen von den bigrams entfernt.
bigram_texts_zeit_online_2017_separated <- bigram_texts_zeit_online_2017 %>%
separate(bigram, c("word1", "word2"), sep = " ")
bigram_texts_zeit_online_2017_filtered <- bigram_texts_zeit_online_2017_separated %>%
filter(!str_detect(word1, pattern = "[[:digit:]]")) %>%
filter(!str_detect(word2, pattern = "[[:digit:]]")) %>%
filter(!is.na(word1))
bigram_texts_zeit_online_2017_counts <- bigram_texts_zeit_online_2017_filtered %>%
count(word1, word2, sort = TRUE)
bigram_texts_zeit_online_2017_united <- bigram_texts_zeit_online_2017_filtered %>%
unite(bigram, word1, word2, sep = " ")
bigram_texts_zeit_online_2017_united %>%
count(bigram, sort = TRUE) %>%
top_n(9) %>%
mutate(bigram = reorder(bigram, n)) %>%
ggplot(aes(bigram, n)) +
geom_col() +
xlab(NULL) +
ylab("Häufigkeit (n)") +
coord_flip() +
theme_minimal()Nach diesem Bearbeitungsschritt zeigen sich die Namen einiger Spitzenpolitiker sowie von regionaler Wahlkreiskandidaten.
top10_words_text_by_years <- tb_text %>%
select(year,word) %>%
filter(!str_detect(word, pattern = "[[:digit:]]")) %>%
count(year, word, sort = TRUE) %>%
group_by_(~ year) %>%
top_n(10)
top10_words_text_by_years %>%
ggplot(aes(word, n)) +
geom_col(aes(fill=as.factor(year))) +
xlab(NULL) +
scale_y_continuous(expand = c(0, 0)) +
coord_flip() +
theme_classic(base_size = 12) +
labs(fill= "Nach Jahr", title="Worthäufigkeiten in Artikeltexten nach Jahren", subtitle="Top10 Token für die Wahljahre") +
theme(plot.title = element_text(lineheight=.8, face="bold")) +
scale_fill_brewer(palette="Set1")Über den gesamten Betrachtungszeitraum hinweg zeigt sich, dass die SPD das größte Volumen an Presseartikeln auf sich vereinigen konnte. Gefolgt wird die SPD von der CDU und mit etwas Abstand der FDP und den Grünen. Auffallend ist, dass im Jahr 2017 die AFD fast auf ein ebenso großes Artikelvolumen kam wie die CDU. Die CSU zeigt ein äußerst geringes Volumen an Berichten, was vielleicht auf darauf zurückgeführt werden kann, dass große bayerische Zeitungen (beispielsweise die Süddeutsche Zeitung) nicht in der WISO-Datenbank vertreten sind.
top10_words_header_by_years <- tb_text %>%
select(year,word) %>%
filter(!str_detect(word, pattern = "[[:digit:]]")) %>%
count(year, word, sort = TRUE) %>%
group_by_(~ year) %>%
top_n(10)
top10_words_header_by_years %>%
ggplot(aes(word, n)) +
geom_col(aes(fill=as.factor(year))) +
xlab(NULL) +
scale_y_continuous(expand = c(0, 0)) +
coord_flip() +
theme_classic(base_size = 12) +
labs(fill= "Nach Jahr", title="Worthäufigkeiten in Artikeltexten nach Jahren", subtitle="Top10 Token für die Wahljahre") +
theme(plot.title = element_text(lineheight=.8, face="bold")) +
scale_fill_brewer(palette="Set1")Bei der Auswertung der Einzelnennungen zeigt sich ein recht ähnliches Bild wie bei der Analyse des Artikelvolumens.
# Filtern der Top10 Zeitungen
publisher_top10_text <- tb_text %>%
add_count(publisher) %>%
filter(!str_detect(word, pattern = "[[:digit:]]")) %>%
filter(dense_rank(-n) <= 10)
publisher_top10_text_count <-
publisher_top10_text %>%
count(publisher)
publisher_top10_text %>%
count(publisher, word, sort = TRUE) %>%
group_by(publisher) %>%
top_n(10) %>%
ggplot(aes(x = word, y = n)) +
geom_col(aes(fill=publisher)) +
xlab(NULL) +
scale_y_continuous(expand = c(0, 0)) +
coord_flip() +
theme_classic(base_size = 12) +
labs(fill= "Nach Verlag", title="Worthäufigkeiten", subtitle="Top10 Token in den Artikeltexten der Top10 Verlage (nach Anzahl der Artikel)") +
theme(plot.title = element_text(lineheight=.8, face="bold")) +
scale_fill_brewer(palette="Set3")# Filtern der Top10 Zeitungen
publisher_top5_head <- tb_header %>% add_count(publisher) %>% filter(dense_rank(-n) <= 5)
publisher_top5_head_count <- publisher_top5_head %>% count(publisher)
publisher_top5_head %>%
count(publisher, word, sort = TRUE) %>%
group_by(publisher) %>%
top_n(3) %>%
ggplot(aes(x = word, y = n)) +
geom_col(aes(fill=publisher)) +
xlab(NULL) +
scale_y_continuous(expand = c(0, 0)) +
coord_flip() +
theme_classic(base_size = 12) +
labs(fill= "Nach Verlag", title="Worthäufigkeiten", subtitle="Top10 Token in den Artikelüberschriften der Top10 Verlage (nach Anzahl der Artikel)") +
theme(plot.title = element_text(lineheight=.8, face="bold")) +
scale_fill_brewer(palette="Set3")library(wordcloud2)
top200_text_wordcloud <- tb_text %>%
count(word) %>%
top_n(200)
# Durch einen Fehler im Paket wordcloud2 werden die Grafiken nicht in das HTML-Dokument durch den Knit-Prozess übertragen.
# Um die HTML Datei trotzdem mit der Grafik zu erzeugen, werden die nachfolgenden Zeilen Code zusätzlich verwendet, um diesen
# Fehler im Paket zu umgehen. Ein mögliches Update des Pakets soll das Problem in der Zukunft lösen. Sofern das Update den Fehler behebt, kann die
# nachfolgende auskommentierte Zeile die darauffolgenden im Codechunk ersetzen.
#wordcloud2(top200_text_wordcloud)
graph_wordcloud2_1 <- wordcloud2(top200_text_wordcloud)
saveWidget(graph_wordcloud2_1, "graph_wordcloud2_1.html", selfcontained = F)
webshot("graph_wordcloud2_1.html", "graph_wordcloud2_1.png", delay = 10, vwidth = 800, vheight = 800)Wie bereits bei der Analyse der Worthäufigkeiten, zeigt sich auch in der Darstellung der Wordcloud eine Mischung aus Parteiennamen, Namen von handelnden Personen, wahlspezifischen Begriffen sowie vereinzelt politischen Themen. Die Daten der Wahltage tauchen ebenfalls auf, könnten aber durch eine Stopword-Behandlung eliminiert werden.
# Alle Wörter des Jahres 2013
top100_text_wordcloud_2013 <- tb_text %>%
filter(year == 2013) %>%
count(word) %>%
top_n(100)
# Durch einen Fehler im Paket wordcloud2 werden die Grafiken nicht in das HTML-Dokument durch den Knit-Prozess übertragen.
# Um die HTML Datei trotzdem mit der Grafik zu erzeugen, werden die nachfolgenden Zeilen Code zusätzlich verwendet, um diesen
# Fehler im Paket zu umgehen. Ein mögliches Update des Paket soll das Problem in der Zukunft lösen. Sofern das Update den Fehler behebt, kann die
# nachfolgende auskommentierte Zeile die darauffolgenden im Codechunk ersetzen.
#wordcloud2(top100_text_wordcloud_2013)
graph_wordcloud2_4 <- wordcloud2(top100_text_wordcloud_2013)
saveWidget(graph_wordcloud2_4, "graph_wordcloud2_4.html", selfcontained = F)
webshot("graph_wordcloud2_4.html", "graph_wordcloud2_4.png", delay = 10, vwidth = 800, vheight = 800)Im Vergleich der beiden Jahre 2013 und 2017 wird die deutliche Fokussierung auf die AFD im Jahr 2017 deutlich.
# Alle Wörter des Jahres 2017
top100_text_wordcloud_2017 <- tb_text %>%
filter(year == 2017) %>%
count(word) %>%
top_n(100)
# Durch einen Fehler im Paket wordcloud2 werden die Grafiken nicht in das HTML-Dokument durch den Knit-Prozess übertragen.
# Um die HTML Datei trotzdem mit der Grafik zu erzeugen, werden die nachfolgenden Zeilen Code zusätzlich verwendet, um diesen
# Fehler im Paket zu umgehen. Ein mögliches Update des Pakets soll das Problem in der Zukunft lösen. Sofern das Update den Fehler behebt, kann die
# nachfolgende auskommentierte Zeile die darauffolgenden im Codechunk ersetzen.
#wordcloud2(top100_text_wordcloud_2017)
graph_wordcloud2_5 <- wordcloud2(top100_text_wordcloud_2017)
saveWidget(graph_wordcloud2_5, "graph_wordcloud2_5.html", selfcontained = F)
webshot("graph_wordcloud2_5.html", "graph_wordcloud2_5.png", delay = 10, vwidth = 800, vheight = 800)Im direkten Vergleich der Jahre 2013 und 2017 zeigt sich deutlich das gestiegene Interesse der Presse an der AFD. Die SPD steht 2017 bei weitem nicht so sehr im Vordergrund wie in der Berichterstattung des Jahres 2013. Davon profitierte der SPD Spitzenkandidat des Jahres 2017 - Martin Schulz - der eine weit größere Pressepräsenz zeigte als sein Vorgänger Steinbrück im Jahre 2013.
# Alle Wörter des Jahres 2017
top100_text_der_tagesspiegel_wordcloud <- tb_text %>%
filter(publisher == "der tagesspiegel") %>%
count(word) %>%
top_n(100)
# Durch einen Fehler im Paket wordcloud2 werden die Grafiken nicht in das HTML-Dokument durch den Knit-Prozess übertragen.
# Um die HTML Datei trotzdem mit der Grafik zu erzeugen, werden die nachfolgenden Zeilen Code zusätzlich verwendet, um diesen
# Fehler im Paket zu umgehen. Ein mögliches Update des Paket soll das Problem in der Zukunft lösen. Sofern das Update den Fehler behebt, kann die
# nachfolgende auskommentierte Zeile die darauffolgenden im Codechunk ersetzen.
#wordcloud2(top100_text_der_tagesspiegel_wordcloud)
graph_wordcloud2_6 <- wordcloud2(top100_text_der_tagesspiegel_wordcloud)
saveWidget(graph_wordcloud2_6, "graph_wordcloud2_6.html", selfcontained = F)
webshot("graph_wordcloud2_6.html", "graph_wordcloud2_6.png", delay = 10, vwidth = 800, vheight = 800)Spontan fällt auf, dass der Tagesspiegel scheinbar besonders gerne über die SPD und kaum über die AFD berichtet.
# Filtern der Top6 Zeitungen
publisher_top6 <- tb_text %>% add_count(publisher) %>% filter(dense_rank(-n) <= 6)
publisher_top6_count <- publisher_top6 %>% count(publisher)
publisher_top6_plot <- publisher_top6 %>%
count(publisher, word, sort = TRUE) %>%
bind_tf_idf(word, publisher, n) %>%
mutate(word = fct_reorder(word, tf_idf))
publisher_top6_plot %>%
group_by(publisher) %>%
top_n(5, tf_idf) %>%
ungroup() %>%
mutate(word = reorder(word, tf_idf)) %>%
ggplot(aes(word, tf_idf, fill = publisher)) +
scale_y_continuous(expand = c(0, 0)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y = "tf-idf") +
facet_wrap(~publisher, ncol = 2, scales = "free") +
coord_flip() +
theme_classic(base_size = 12) +
labs(fill= "Author",
title = "Häufigkeit nach TF-IDF (inverse Dokumenthäufigkeit)",
subtitle="Top5 Wörter in den Artikeltexten der Top6 Verlage mit den meisten Artikeln",
x= NULL,
y= "tf-idf") +
theme(plot.title = element_text(lineheight=.8, face="bold")) +
scale_fill_brewer(palette="Set3") Eine TF-IDF Analyse macht bei einer Analyse dieser Art nicht sonderlich viel Sinn. Hintergrund: Die Vorauswahl der Presseberichte geschah entlang der Thematik ‘Bundestagswahl’. Das bedeutet, dass der gesamte Textcorpus sich mit dem Thema ‘Wahlen’ auseinandersetzt. Unterschiede zwischen einzelnen Publikationen ergeben sich dadurch hauptsächlich durch die lokalen Bezüge wie Ortsnamen oder Namen der lokalen Abgeordneten.
# Filtern der Top6 Zeitungen
publisher_top6_header <- tb_header %>% add_count(publisher) %>% filter(dense_rank(-n) <= 6)
publisher_top6_header_count <- publisher_top6_header %>% count(publisher)
publisher_top6_header_plot <- publisher_top6_header %>%
count(publisher, word, sort = TRUE) %>%
bind_tf_idf(word, publisher, n) %>%
mutate(word = fct_reorder(word, tf_idf))
publisher_top6_header_plot %>%
group_by(publisher) %>%
top_n(5, tf_idf) %>%
ungroup() %>%
mutate(word = reorder(word, tf_idf)) %>%
ggplot(aes(word, tf_idf, fill = publisher)) +
scale_y_continuous(expand = c(0, 0)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y = "tf-idf") +
facet_wrap(~publisher, ncol = 2, scales = "free") +
coord_flip() +
theme_classic(base_size = 12) +
labs(fill= "Author",
title = "Häufigkeit nach TF-IDF (inverse Dokumenthäufigkeit)",
subtitle="Top5 Wörter in den Artikelüberschriften der Top6 Verlage mit den meisten Artikeln",
x= NULL,
y= "tf-idf") +
theme(plot.title = element_text(lineheight=.8, face="bold")) +
scale_fill_brewer(palette="Set3") # Generieren der bigrams des Jahres 2017
bigrams_der_tagesspiegel <- presse_cleaned %>%
filter(publisher == "der tagesspiegel") %>%
unnest_tokens(bigram, text, token = "ngrams", n = 2)
# Trennen der Wörter
bigrams_der_tagesspiegel_separated <- bigrams_der_tagesspiegel %>%
separate(bigram, c("word1", "word2"), sep = " ")
# Filtern von Stopwords und fehlenden Werten
bigrams_der_tagesspiegel_filtered <- bigrams_der_tagesspiegel_separated %>%
filter(!word1 %in% all_stopword$word) %>%
filter(!word2 %in% all_stopword$word) %>%
filter(!str_detect(word1, pattern = "[[:digit:]]")) %>%
filter(!str_detect(word2, pattern = "[[:digit:]]")) %>%
filter(!is.na(word1))
# Anzahl der bigrams:
bigrams_der_tagesspiegel_counts <- bigrams_der_tagesspiegel_filtered %>%
count(word1, word2, sort = TRUE) %>% filter(n > 14)
# Filtern für geläufige Wortkombinationen
bigrams_der_tagesspiegel_graph <-
bigrams_der_tagesspiegel_counts %>%
graph_from_data_frame()Die dargestellten bigrams kommen mindestens 15x in den Artikeln vor.
set.seed(1)
ggraph(bigrams_der_tagesspiegel_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)set.seed(2)
arrow_set <- grid::arrow(type = "closed", length = unit(.15, "inches"))
ggraph(bigrams_der_tagesspiegel_graph, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = arrow_set, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "lightblue", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1) +
theme_void()Bei den Bigrams fällt auf, dass es sich sehr häufig um eine Kombination von Vor- und Nachnamen bekannter Politiker handelt. Auch häufig auftretende Wortkombinationen - z.B. ‘Hartz IV’, ‘rot-grün’ oder CDU-CSU - sind zu finden.
# Generieren der bigrams des Jahres 2017
bigrams_jahr_2017 <- presse_cleaned %>%
filter(year == "2017") %>%
unnest_tokens(bigram, text, token = "ngrams", n = 2)
# Trennen der Wörter
bigrams_jahr_2017_separated <- bigrams_jahr_2017 %>%
separate(bigram, c("word1", "word2"), sep = " ")
# Filtern von Stopwords und fehlender Werte
bigrams_jahr_2017_filtered <- bigrams_jahr_2017_separated %>%
filter(!word1 %in% all_stopword$word) %>%
filter(!word2 %in% all_stopword$word) %>%
filter(!str_detect(word1, pattern = "[[:digit:]]")) %>%
filter(!str_detect(word2, pattern = "[[:digit:]]")) %>%
filter(!is.na(word1))
# Anzahl der bigrams
bigrams_jahr_2017_counts <-
bigrams_jahr_2017_filtered %>%
count(word1, word2, sort = TRUE) %>%
filter(n > 39)
# Filtern der geläufigen Wortkombinationen
bigrams_jahr_2017_graph <- bigrams_jahr_2017_counts %>%
graph_from_data_frame()Die dargestellten Token sind mindestens 40x in den Artikeln vertreten.
set.seed(3)
ggraph(bigrams_jahr_2017_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)set.seed(4)
arrow_set <- grid::arrow(type = "closed", length = unit(.15, "inches"))
ggraph(bigrams_jahr_2017_graph, layout = "fr") +
geom_edge_link(aes(edge_alpha = n), show.legend = FALSE,
arrow = arrow_set, end_cap = circle(.07, 'inches')) +
geom_node_point(color = "lightblue", size = 5) +
geom_node_text(aes(label = name), vjust = 1, hjust = 1) +
theme_void()Auch hier sind wieder ähnliche Muster wie oben zu erkennen. Auffällig ist die größere Baumstruktur, welche die Namen der beiden Spitzenkandidaten für das Kanzleramt miteinander verbindet.
bigrams_over_all_years <-
presse_cleaned %>%
unnest_tokens(bigram, text, token = "ngrams", n = 2)
bigrams_over_all_years_separated <-
bigrams_over_all_years %>%
separate(bigram, c("word1", "word2"), sep = " ")
# Filtern von Stopwords und fehlenden Werte
bigrams_over_all_years_separated_filtered <-
bigrams_over_all_years_separated %>%
filter(!word1 %in% all_stopword$word) %>%
filter(!word2 %in% all_stopword$word) %>%
filter(!str_detect(word1, pattern = "[[:digit:]]")) %>%
filter(!str_detect(word2, pattern = "[[:digit:]]")) %>%
filter(!is.na(word1))
bigrams_over_all_years_counts <-
bigrams_over_all_years_separated_filtered %>%
group_by(year,word1,word2) %>%
summarise(count = n()) %>%
ungroup() %>%
rename(n = count) %>%
filter(n > 49)
bigrams_over_all_years_graph <-
graph_from_data_frame(bigrams_over_all_years_counts)Bei der Darstellung behalten wir das Attribut “Jahr”, welches entsprechend der Verwendung in dem Jahr eingefärbt werden. Alle dargestellten Token wurden mindestens 50x in Artikeln genannt.
set.seed(6)
ggraph(bigrams_over_all_years_graph, layout = 'kk', maxiter = 100) +
geom_edge_link(aes(colour = factor(bigrams_over_all_years_counts$year))) +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1) +
scale_color_manual(name="Type of Activity") +
theme(legend.title = element_blank(), legend.text = element_text(size = 14)) +
coord_fixed()Bei dieser Darstellung zeigt sich sehr schön, welche Personennamen im jeweiligen Wahljahr im Vordergrund standen. Vereinzelt lassen sich auch wieder bestimmte Themen - z.B. ‘Hartz’ und ‘Soziales’ im Jahr 2005 - zueinander zuordnen.
trigrams_year_2017 <- presse_cleaned %>%
#filter(year == "2017") %>%
unnest_tokens(trigram, text, token = "ngrams", n = 3)
trigram_texts_2017_separated <- trigrams_year_2017 %>%
separate(trigram, c("word1", "word2", "word3"), sep = " ")
trigram_texts_2017_cdu_filtered <- trigram_texts_2017_separated %>%
filter(!word1 %in% all_stopword$word) %>%
filter(!word2 %in% all_stopword$word) %>%
filter(!word3 %in% all_stopword$word) %>%
filter(!str_detect(word1, pattern = "[[:digit:]]")) %>%
filter(!str_detect(word2, pattern = "[[:digit:]]")) %>%
filter(!str_detect(word3, pattern = "[[:digit:]]")) %>%
filter(word1 == "cdu" | word2 == "cdu" | word3 == "cdu")
trigram_texts_2017_cdu_counts <- trigram_texts_2017_cdu_filtered %>%
count(word1, word2, word3, sort = TRUE)
trigram_texts_2017_cdu_united <- trigram_texts_2017_cdu_counts %>%
unite(trigram, word1, word2, word3, sep = " ") %>% top_n(10)
trigram_texts_2017_cdu_united %>%
count(trigram, sort = TRUE) %>%
mutate(trigram = reorder(trigram, n)) %>%
ggplot(aes(trigram, n)) +
geom_col() +
xlab(NULL) +
ylab("Häufigkeit (n)") +
coord_flip() +
labs(title = "Trigrams aus dem Jahr 2017 mit dem Begriff 'CDU'") +
theme_minimal()Bei der Analyse der Trigrams stehen eindeutig Kombinationen von Personennamen und Parteien im Vordergrund. Insgesamt fällt auf, dass die Häufigkeit solcher Trigrams sehr niedrig ist.
# Generieren von Wortpaaren nach Publikation
wortpaare_jahr_1990_count <- tb_text %>%
filter(year == "1990") %>%
pairwise_count(word, publisher, sort = TRUE)
# Generieren von Wortpaaren mit Korrelation (zwischen 0 und 1) nach Publikation
wortpaare_jahr_1998_count <- tb_text %>%
filter(year == "1998") %>%
pairwise_count(word, publisher, sort = TRUE)Nachfolgend sind Wortpaare abgebildet, welche mehr als 4x zusammen genannt werden.
set.seed(7)
wortpaare_jahr_1990_n4 <- filter(wortpaare_jahr_1990_count, n >= 4)
wortpaare_jahr_1990_n4_graph <- graph_from_data_frame(wortpaare_jahr_1990_n4)
ggraph(wortpaare_jahr_1990_n4_graph, layout = "fr") +
geom_edge_link(aes(edge_alpha = n, edge_width = n), edge_colour = "cyan4") +
geom_node_point(size = 5) +
geom_node_text(aes(label = name), repel = TRUE,
point.padding = unit(0.2, "lines")) +
theme_void()Diese Art der Darstellung zeigt sehr anschaulich, welche Begriffe sehr häufig und sehr häufig im Zusammenhang auftauchen. Diese Begriffe stehen im Zentrum der Visualisierung. Die weiter außen stehenden Begriffe tauchen ebenfalls häufig auf, Kombinationen mit den Wörtern im Zentrum sind allerdings etwas weniger häufig. Im konkreten Fall zeigt sich, dass die Parteien bei der Wahl 1990 im Zentrum der Berichterstattung standen. Allerdings spielte die DDR zu der Zeit noch eine wichtige Rolle in der Berichterstattung und auch das Datum der Wahl - der 2. Dezember 1990 ist zu erkennen.
In dem Aufruf werden die Items zunächst auf den Begriff “DDR” gefiltert, bevor diese in einem Balkendiagramm dargestellt werden.
wortpaare_jahr_1990_count %>%
filter(item1 %in% "ddr") %>%
filter(!str_detect(item2, pattern = "[[:digit:]]")) %>%
top_n(1) %>%
ungroup() %>%
mutate(item2 = reorder(item2, n)) %>%
ggplot(aes(item2, n)) +
geom_bar(stat = "identity") +
facet_wrap(~ item1, scales = "free") +
xlab(NULL) +
ylab("Häufigkeit (n)") +
coord_flip() +
labs(title = "Wortpaare aus dem Jahr 1990 mit dem Begriff 'DDR'") +
theme_minimal()Auch hier zeigen sich wieder relativ geringe Häufigkeiten, was vermutlich auch der geringen Anzahl von Presseberichten aus dem Jahr 1990 geschuldet ist. Deshalb ist die Aussagekraft dieser speziellen Analyse eher gering.
Die Themen “Digitalisierung” und “Internet” waren im Jahr 1998 für den Wahlkampf und die Berichterstattung kaum relevant. Die nachfolgende Darstellung zeigt Wortpaare, welche mehr als 6x vorgekamen.
set.seed(8)
wortpaare_jahr_1998_internet <- filter(wortpaare_jahr_1998_count, item1 %in% c("internet", "digitalisierung", "digital")) %>% filter(n > 6)
wortpaare_jahr_1998_internet_graph <- graph_from_data_frame(wortpaare_jahr_1998_internet)
ggraph(wortpaare_jahr_1998_internet_graph, layout = "fr") +
geom_edge_link(aes(edge_alpha = n, edge_width = n), edge_colour = "cyan4") +
geom_node_point(size = 5) +
geom_node_text(aes(label = name), repel = TRUE,
point.padding = unit(0.2, "lines")) +
theme_void()In dieser Darstellung lässt sich gut erkennen, welche anderen Begriffe häufig im Umfeld eines bestimmten Themas wiederfinden. Dadurch kann man im Idealfall Rückschlüsse ziehen, welche Parteien oder Politiker sich zu diesem Thema äußern.